<template>
  <n-data-table
    class="ie-table"
    :columns="columns"
    :loading="isFetching"
    :data="data.items"
    :scroll-x="props.width"
    :pagination="data.pagination"
    :paging="false"
    :single-line="false"
    :row-key="rowKey"
    @update:page="handlePageChange"
    @update:sorter="handleSorterChange"
    v-model:checked-row-keys="rawCheckedRowKeys"
    @update:checked-row-keys="handleUpdateRowKeys"
    remote
  >
  </n-data-table>
</template>

<script>
export const ACTIONS = [
  { key: 'download', name: '下载', type: 'info' },
  { key: 'edit', name: '编辑', type: 'success' },
  { key: 'view', name: '查看', type: 'success' },
  { key: 'delete', name: '删除', usePopconfirm: true, type: 'error' },
  { key: 'revert', name: '还原', usePopconfirm: true, type: 'warning' },
]
</script>

<script setup>
import { ref, reactive, watch, h, resolveComponent } from 'vue'
import { useRoute } from 'vue-router'
import { NDataTable } from 'naive-ui'
import { find } from 'lodash-es'

import { createPageQuery, usePageQuery } from '/@/graphql'
import { modelValidator } from '/@/model'
import normalizeColumns from '/@/utils/normalize-columns'
import { toVars } from '/@/utils/helper'

const props = defineProps({
  model: {
    validator: modelValidator,
    required: true
  },
  usePage: {
    type: Boolean,
    default: true
  },
  actions: {
    type: Array,
    default: () => []
  },
  rowKey: {
    type: Function
  },
  checkedRowKeys: {
    type: Array,
    default: () => []
  },
  width: {
    type: [Number, String],
    default: 1200
  },
  defaultWhere: {
    type: Object,
    default: () => ({})
  }
})

const emit = defineEmits([
  'update:checked-row-keys',
  ...ACTIONS.map(({ key }) => `${key}:row`)
])

const route = useRoute()

const query = createPageQuery(props.model)
const variables = reactive({
  page: 1,
  pageSize: 10,
  orderBy: {},
  where: {
    ...props.defaultWhere,
    ...(toVars(route.query) || {}),
  }
})

watch(
  () => route.query,
  routeQuery => {
    variables.where = {
      ...props.defaultWhere,
      ...toVars(routeQuery)
    }
  }
)

const { isFetching, data, execute } = usePageQuery({
  query,
  variables
})
const refresh = () => execute()

defineExpose({ refresh })

const columns = normalizeColumns(props.model.columns)

// use selection
const rawCheckedRowKeys = ref(props.checkedRowKeys)

if (typeof props.rowKey === 'function') {
  columns.unshift({
    type: 'selection',
    fixed: 'left'
  })
}

const actions = props.actions.filter(
  action => ACTIONS.some(({ key }) => key === action)
)

// add actions column
if (actions.length) {
  const NButtonGroup = resolveComponent('n-button-group')
  const NButton = resolveComponent('n-button')
  const NPopconfirm = resolveComponent('n-popconfirm')

  columns.push({
    title: '操作',
    key: 'actions',
    align: 'center',
    fixed: 'right',
    width: actions.length * 40 + 30,
    render(row) {
      const children = []

      actions.forEach(action => {
        const onClick = () => emit(`${action}:row`, row, refresh)
        const {
          name,
          type,
          usePopconfirm = false
        } = find(ACTIONS, ['key', action]) || {}

        if (
          !name ||
          (row.deleted_at && action === 'delete') ||
          (row.deleted_at === null && action === 'revert')
        ) return

        children.push(
          usePopconfirm
          ? h(NPopconfirm, {
            onPositiveClick: onClick
          }, {
            default: () => `请确定是否${name}？`,
            trigger: () => h(NButton, {
              size: 'tiny',
              secondary: true,
              type
            }, { default: () => name })
          })
          : h(NButton, {
            size: 'tiny',
            secondary: true,
            type,
            onClick
          }, { default: () => name })
        )
      })

      return h(NButtonGroup, {}, {
        default: () => children
      })
    }
  })
}

function handlePageChange(page) {
  variables.page = page
}

function handleSorterChange(sorter) {
  const {
    columnKey,
    order
  } = sorter

  if (order) {
    variables.orderBy[columnKey] = order === 'descend' ? 'desc' : 'asc'
  } else {
    variables.orderBy[columnKey] = undefined
  }
}

function handleUpdateRowKeys(evt) {
  rawCheckedRowKeys.value = evt
  emit('update:checked-row-keys', evt)
}
</script>
